package com.dm.cloud.images.util;


import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.model.AuthConfig;
import com.dm.cloud.core.exception.CustomException;
import com.dm.cloud.images.common.mode.ImageMode;
import com.dm.cloud.images.common.mode.ImageTag;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Component
@ConfigurationProperties(prefix = "dm.images.config")
@Data
@Slf4j
public class RepositoryUtils {
    /**
     * harbor服务地址
     */
    private String harborServer;

    /**
     * harbor 服务端口
     */
    private Integer harborPort = 80;

    /**
     * harbor 是否开启ssl
     */
    private Boolean harborSsl = false;

    /**
     * harbor账号
     */
    private String harborUsername;
    /**
     * harbor密码
     */
    private String harborPwd;
    /**
     * harbor仓库名
     */
    private String harborRepository;

    /**
     * harbor认证
     *
     * @return
     */
    public AuthConfig harborAuth() {
        AuthConfig autoConfig = new AuthConfig().withRegistryAddress(harborServer).withUsername(harborUsername).withPassword(harborPwd);
        return autoConfig;
    }

    private String urlPrefix() {
        return harborSsl ? "https://" : "http://";
    }

    /**
     * 获取harbor服务的http地址
     *
     * @return
     */
    private String serverAddress() {
        return urlPrefix() + harborServer + ":" + harborPort;
    }

    /**
     * 向harbor推送镜像
     *
     * @param client
     * @param localImageTag
     * @return
     */
    public String pushByLocal(DockerClient client, String localImageTag) {
        int nameStart = localImageTag.lastIndexOf("/");
        String localTag = null;
        if (nameStart != -1) {
            localTag = localImageTag.substring(nameStart + 1);
        } else {
            localTag = localImageTag;
        }
//        2023-09-05.11h_20m
        if (!localTag.contains(":")) {
            localTag = localTag + ":" + DateUtil.format(new Date(), "yyyy-MM-dd.HHh_mmm");
        }
        //添加前缀,形成镜像名
        String localNewName = harborServer + "/" + harborRepository + "/" + localTag.split(":")[0];
        String localNewTag = localTag.split(":")[1];
        client.tagImageCmd(localImageTag, localNewName, localNewTag).exec();
        String localImageName = localNewName + ":" + localNewTag;
        //执行上传操作
        try {
            client.pushImageCmd(localImageName)
                    .withAuthConfig(harborAuth())
                    .start().awaitCompletion();
        } catch (InterruptedException e) {
            e.printStackTrace();
            throw new CustomException("镜像上传到仓库失败");
        }
        return localImageName;
    }

    /**
     * 查询镜像列表
     *
     * @param page      页码，1开始
     * @param page_size 分页条数
     * @param sort      排序：-creation_time,project_id  多个字段用逗号分割
     * @param q         条件:Query string to query resources. Supported query patterns are "exact match(k=v)", "fuzzy match(k=~v)", "range(k=[min~max])", "list with union releationship(k={v1 v2 v3})" and "list with intersetion relationship(k=(v1 v2 v3))". The value of range and list can be string(enclosed by " or '), integer or time(in format "2020-04-09 02:36:00"). All of these query patterns should be put in the query string "q=xxx" and splitted by ",". e.g. q=k1=v1,k2=~v2,k3=[min~max]
     * @return
     */
    public List<ImageMode> searchImages(Integer page, Integer page_size, String sort, String q) {
        String searchUrl = serverAddress() + "/api/v2.0/projects/" + harborRepository + "/repositories";

        HttpRequest request = HttpRequest.get(searchUrl).basicAuth(harborUsername, harborPwd);
        if (page == null || page < 0) {
            page = 1;
        }
        if (page_size == null || page_size < 0) {
            page_size = 10;
        }
        request.form("page", page);
        request.form("page_size", page_size);
        if (StrUtil.isNotEmpty(sort)) {
            request.form("sort", sort);
        }
        if (StrUtil.isNotEmpty(q)) {
            request.form("q", q);
        }
        try {
            HttpResponse resp = request.executeAsync();
            String body = resposeStatusHandler(resp);

            List<ImageMode> arr = JSONArray.parseArray(body, ImageMode.class);
            if(arr!=null && !arr.isEmpty()){
                for (ImageMode imageMode : arr) {
                    if(imageMode.getName().startsWith(harborRepository)){
                        imageMode.setName(imageMode.getName().substring(harborRepository.length()+1));
                    }
                }
            }
            return arr;
        }catch (IORuntimeException e){
            e.printStackTrace();
            throw new CustomException("镜像服务连接失败!");
        }catch (CustomException e){
            throw e;
        }catch (Exception e){
            e.printStackTrace();
            throw new CustomException("镜像查询出错！");
        }
    }

    /**
     * 删除镜像
     *
     * @param imageName 不带tag
     */
    public void deleteImage(String imageName) {
        String searchUrl = serverAddress() + "/api/v2.0/projects/" + harborRepository + "/repositories/" + imageName;
        HttpResponse resp = HttpRequest.delete(searchUrl).basicAuth(harborUsername, harborPwd).executeAsync();
        resposeStatusHandler(resp);
    }

    /**
     * 查询单条镜像接口，单仓库的自动机器人账户似乎不可用。
     *
     * @param imageName
     * @return
     */
    public ImageMode imageDetail(String imageName) {
        String searchUrl = serverAddress() + "/api/v2.0/projects/" + harborRepository + "/repositories/" + imageName;
        HttpResponse resp = HttpRequest.get(searchUrl).basicAuth(harborUsername, harborPwd).executeAsync();
        resposeStatusHandler(resp);
        if (StrUtil.isNotEmpty(resp.body())) {
            return JSONObject.parseObject(resp.body(), ImageMode.class);
        }
        return null;
    }

    /**
     * 获取镜像的所有tag
     *
     * @param imageName
     * @return
     */
    public List<ImageTag> imageTags(String imageName) {
        JSONArray artifacts = imageArtifacts(imageName);
        List<ImageTag> tags = new ArrayList<>();
        for (int i = 0; i < artifacts.size(); i++) {
            JSONObject artifactItem = artifacts.getJSONObject(i);
            String digest = artifactItem.containsKey("digest") ? artifactItem.getString("digest") : "";
            long size = artifactItem.getLongValue("size", 0);
            if (artifactItem.containsKey("tags")) {
                JSONArray tagsArr = artifactItem.getJSONArray("tags");
                if(tagsArr==null || tagsArr.isEmpty()){
                    continue;
                }
                for (int i1 = 0; i1 < tagsArr.size(); i1++) {
                    JSONObject tageItem = tagsArr.getJSONObject(i1);
                    ImageTag tag = tageItem.toJavaObject(ImageTag.class);
                    tag.setDigest(digest);
                    tag.setSize(size);
                    tag.setImage_name(imageName);
                    tags.add(tag);
                }
            }
        }
        return tags;
    }

    /**
     * 删除tag
     * @param digest
     * @param tag
     */
    public void deleteTags(String digest,String imageName,String tag) {
        String searchUrl = serverAddress() + "/api/v2.0/projects/"+harborRepository
                +"/repositories/"+imageName
                +"/artifacts/"+digest
                +"/tags/" + tag;
        HttpResponse resp = HttpRequest.delete(searchUrl).basicAuth(harborUsername, harborPwd).executeAsync();
        resposeStatusHandler(resp);
    }

    /**
     * 返回镜像详细信息
     *
     * @param imageName
     * @return
     */
    public JSONArray imageArtifacts(String imageName) {
//        [
//                {
//                    "accessories": null,
//                        "addition_links": {
//                    "build_history": {
//                        "absolute": false,
//                                "href": "/api/v2.0/projects/equip-test/repositories/integration-qbcl-ui/artifacts/sha256:1ff442f5dcd1b61443d24b36d58dbba68b3c702f54579f8124fc35b74ba90c5e/additions/build_history"
//                    }
//                },
//                    "digest": "sha256:1ff442f5dcd1b61443d24b36d58dbba68b3c702f54579f8124fc35b74ba90c5e",
//                        "extra_attrs": {
//                            "architecture": "amd64",
//                            "author": "NGINX Docker Maintainers <docker-maint@nginx.com>",
//                            "config": {
//                                "ArgsEscaped": true,
//                                "Cmd": [
//                                "nginx",
//                                "-g",
//                                "daemon off;"
//                        ],
//                        "Env": [
//                        "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
//                                "NGINX_VERSION=1.15.3-1~stretch",
//                                "NJS_VERSION=1.15.3.0.2.3-1~stretch"
//                        ],
//                        "ExposedPorts": {
//                            "80/tcp": {}
//                        },
//                        "Labels": {
//                            "maintainer": "NGINX Docker Maintainers <docker-maint@nginx.com>"
//                        },
//                        "StopSignal": "SIGTERM"
//                    },
//                    "created": "2023-11-30T04:42:25.828872625Z",
//                            "os": "linux"
//                },
//                    "icon": "sha256:0048162a053eef4d4ce3fe7518615bef084403614f8bca43b40ae2e762e11e06",
//                        "id": 11,
//                        "labels": null,
//                        "manifest_media_type": "application/vnd.docker.distribution.manifest.v2+json",
//                        "media_type": "application/vnd.docker.container.image.v1+json",
//                        "project_id": 2,
//                        "pull_time": "0001-01-01T00:00:00.000Z",
//                        "push_time": "2023-12-22T01:23:11.376Z",
//                        "references": null,
//                        "repository_id": 11,
//                        "size": 71499452,
//                        "tags": [
//                    {
//                        "artifact_id": 11,
//                            "id": 11,
//                            "immutable": false,
//                            "name": "v0.0.1.20231130",
//                            "pull_time": "0001-01-01T00:00:00.000Z",
//                            "push_time": "2023-12-22T01:23:11.535Z",
//                            "repository_id": 11
//                    }
//                ],
//                    "type": "IMAGE"
//                }
//        ]
        String searchUrl = serverAddress() + "/api/v2.0/projects/" + harborRepository + "/repositories/" + imageName + "/artifacts/";
        HttpResponse resp = HttpRequest.get(searchUrl).basicAuth(harborUsername, harborPwd).executeAsync();
        resposeStatusHandler(resp);
        return JSONArray.parseArray(resp.body());
    }




    /**
     * 验证接口返回状态
     *
     * @param resp
     */
    private String resposeStatusHandler(HttpResponse resp) {
        if (resp.getStatus() != 200) {
            String bodyStr = resp.body();
            List<String> errStrs = new ArrayList<>();
            if (StrUtil.isNotEmpty(bodyStr)) {
                JSONObject object = JSONObject.parseObject(bodyStr);
                if (object.containsKey("errors")) {
                    JSONArray errors = object.getJSONArray("errors");
                    for (int i = 0; i < errors.size(); i++) {
                        JSONObject errorItem = errors.getJSONObject(i);
                        if (errorItem.containsKey("message")) {
                            String errorStr = errorItem.getString("message");
                            if (errorStr.contains("unauthorized")) {
                                errStrs.add("镜像仓库权限不足!");
                            } else if (errorStr.matches("repository .*? not found")) {
                                String imageName = ReUtil.get("repository (.*?) not found", errorStr, 1);
                                if (imageName.startsWith(harborRepository)) {
                                    imageName = imageName.substring(harborRepository.length() + 1);
                                }
                                errStrs.add("镜像不存在" + imageName);
                            } else if (errorStr.contains("forbidden")) {
                                errStrs.add("没有执行权限");
                            } else if(errorStr.contains("page_size in query should be less than or equal to 100")){
                                errStrs.add("每次最多只能查询100条数据");
                            } else {
                                errStrs.add(errorStr);
                            }
                        }

                    }
                }
            }
            if (errStrs.isEmpty()) {
                throw new CustomException("接口访问失败!");
            } else {
                throw new CustomException(String.join(";", errStrs));
            }
        }
        return resp.body();
    }

    public String repositoryImage(String name,String tag){
        return harborServer + "/" + harborRepository + "/" + name+":"+tag;
    }

    //查询镜像tag详情
    //http://192.168.239.130/api/v2.0/projects/equip-test/repositories/integration-cplatform-ui/artifacts/sha256%3Adc6d2507bb71b93a1b78b16e2a4296e402da4ea1f5052b1f361b7a62c75d447d?page=1&page_size=10&with_tag=true&with_label=false&with_scan_overview=false&with_accessory=false&with_signature=false&with_immutable_status=false
    public JSONObject tagDetail(String imageName,String sha256Ids){
        String searchUrl = serverAddress() + "/api/v2.0/projects/" + harborRepository + "/repositories/" + imageName + "/artifacts/"+sha256Ids+"?with_tag=false&with_scan_overview=true&with_label=true&with_immutable_status=true";
        HttpResponse resp = HttpRequest.get(searchUrl).basicAuth(harborUsername, harborPwd).executeAsync();
        resposeStatusHandler(resp);
        return JSONObject.parseObject(resp.body());
    }

}